package com.ryl.yomall.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ryl.yomall.model.cart.CartInfo;
import com.ryl.yomall.model.common.constant.RedisConst;
import com.ryl.yomall.model.common.util.AuthContextHolder;
import com.ryl.yomall.model.common.util.HttpClientUtil;
import com.ryl.yomall.model.enums.OrderStatus;
import com.ryl.yomall.model.enums.PaymentWay;
import com.ryl.yomall.model.enums.ProcessStatus;
import com.ryl.yomall.model.order.OrderDetail;
import com.ryl.yomall.model.order.OrderInfo;
import com.ryl.yomall.model.product.SpuInfo;
import com.ryl.yomall.order.config.DeadLetterMQConfig;
import com.ryl.yomall.order.mapper.CartInfoMapper;
import com.ryl.yomall.order.mapper.OrderDetailMapper;
import com.ryl.yomall.order.mapper.OrderInfoMapper;
import com.ryl.yomall.order.service.OrderService;
import com.ryl.yomall.rabbitmq.constant.MQConstant;
import com.ryl.yomall.rabbitmq.service.RabbitService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Date 19:30
 * @Author ryl
 */

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;
    @Value ( "${ware.url}" )
    private String wareUrl;

    //保存订单
    @Override
    @Transactional
    public Long saveOrderInfo(OrderInfo orderInfo) {
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus( OrderStatus.UNPAID.name());
        String outTradeNo = "Yo" + System.currentTimeMillis()  + new Random ().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setCreateTime(new Date ());
        // 创建时间 定义为1天后失效
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR, 2);//追加时间
        orderInfo.setExpireTime(calendar.getTime());

        orderInfo.setProcessStatus( ProcessStatus.UNPAID.name());
        // 获取订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        StringBuffer tradeBody = new StringBuffer();
        for (OrderDetail orderDetail : orderDetailList) {
            tradeBody.append(orderDetail.getSkuName()+" ");
        }
        if (tradeBody.toString().length()>100){
            orderInfo.setTradeBody(tradeBody.toString().substring(0,100));
        }else {
            orderInfo.setTradeBody(tradeBody.toString());
        }

        orderInfoMapper.insert(orderInfo);

        //保存订单详情
        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        }
        //3.3删除购物车DB  删除当前提交了订单的购物车中商品  分布式事务问题
//        delete from cart_info where user_id = 3 and sku_id in (5,8)
        //////////////////////////////////////////////
//        delete from cart_info where
//        (user_id = 3 and sku_id = 5) OR (user_id = 3 and sku_id = 8)
        QueryWrapper<CartInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",orderInfo.getUserId());
        List<String> skuIdList = orderDetailList.stream()
                .map(orderDetail -> orderDetail.getSkuId().toString()).
                        collect( Collectors.toList());
        queryWrapper.in("sku_id",skuIdList);
        cartInfoMapper.delete ( queryWrapper );
        //删除缓存
        redisTemplate.opsForHash().delete( RedisConst.USER_KEY_PREFIX
                + orderInfo.getUserId() + RedisConst.USER_CART_KEY_SUFFIX,skuIdList.toArray());
        // 3.5发消息（延迟消息）  RabbitMQ 面试  死信队列   延迟插件
        //发送延迟消息 2 个小时取消订单 生成二维码一般是二个小时
        rabbitService.sendDeadLetterMessage ( DeadLetterMQConfig.EXCHANGE_DIRECT_ORDER_CANCEL,DeadLetterMQConfig.ROUTING_ORDER_CANCEL1,
                orderInfo.getId(),2*60*60 );
        return orderInfo.getId();
    }

    //判断仓库是否还有货
    @Override
    public Boolean hasStock(Long skuId ,Integer skuNum) {

        //远程调用仓库,仓库接口调用
        return "1".equals ( HttpClientUtil.doGet ( wareUrl+"/hasStock?skuId="+
                skuId+"&num="+skuNum) );

    }

    //取消订单
    @Override
    public void cancelOrder(Long orderId) {

        //幂等性问题
        //1.不能重复提交
        //2.不能修改已支付订单
         // ①查询订单状态
         //订单状态是未支付改成已关闭,否则不做任何操作
        OrderInfo orderInfo = getOrderInfo ( orderId );
        if(orderInfo !=null){
            if(orderInfo.getOrderStatus ().equals ( OrderStatus.UNPAID.name () )){
                orderInfo.setProcessStatus ( ProcessStatus.CLOSED.name () );
                orderInfo.setOrderStatus ( OrderStatus.CLOSED.name () );
                orderInfoMapper.updateById ( orderInfo );
            }
        }


    }



    @Override
    public OrderInfo getOrderInfo(Long orderId){
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderId);
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(queryWrapper);
        orderInfo.setOrderDetailList(orderDetailList);
        return orderInfo;

    }

    /**
     * 查询所有订单,并分页
     */
    @Override
    public Map getOrderPageList(Integer page ,Integer limit) {
        Map<String,Object> map=new HashMap<> (  );
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes ( );
        HttpServletRequest request = requestAttributes.getRequest ( );
        String userId = AuthContextHolder.getUserId ( request );
        if(StringUtils.isEmpty ( userId )){
             userId=AuthContextHolder.getUserTempId ( request );
        }
        QueryWrapper<OrderInfo> queryWrapper=new QueryWrapper<OrderInfo> ( );
        queryWrapper.eq ( "user_id",userId );

        IPage<OrderInfo> orderInfoIPage = orderInfoMapper.selectPage ( new Page<OrderInfo> ( page ,limit ) ,queryWrapper );
        List<OrderInfo> records = orderInfoIPage.getRecords ( );
        records= records.stream ( ).map ( orderInfo -> {
            QueryWrapper<OrderDetail> queryWrapper1 = new QueryWrapper<> ( );
            queryWrapper1.eq ( "order_id" ,orderInfo.getId ( ));
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList ( queryWrapper1 );
            orderInfo.setOrderDetailList ( orderDetailList );
            return orderInfo;
        } ).collect ( Collectors.toList ( ) );
        map.put ( "records",records );
        map.put ( "pages", orderInfoIPage.getPages ());
        return map;
    }

    //更新订单的状态
    @Override
    public void updateOrderStatus(Long orderId ,ProcessStatus paid) {
        OrderInfo orderInfo = new OrderInfo ();
        orderInfo.setId ( orderId );
        orderInfo.setOrderStatus ( paid.name () );
        orderInfoMapper.updateById (orderInfo  );
        //MQ 生产端,发送消息给仓库
        rabbitService.sendMessage( MQConstant.EXCHANGE_DIRECT_WARE_STOCK,
                MQConstant.ROUTING_WARE_STOCK,
                JSONObject.toJSONString(initWareOrder(orderInfo.getId())));
    }

    @Override
    public List<OrderInfo> orderSplit(Long orderId ,String wareSkuMap) {
        //订单详情表   skuId 1  skuId 5   同一张订单里
        //1:订单主表 原订单是不变了  原订单父订单 产生2张子订单   保存2条新的订单主表
        //2:订单详情表  修改订单主表的外键
        //[{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        List<Map> mapList = JSONObject.parseArray(wareSkuMap, Map.class);

        //原订单
        OrderInfo originOrderInfo = getOrderInfo (orderId);
        //原订单详情集合
        List<OrderDetail> originOrderDetailList = originOrderInfo.getOrderDetailList();

        //
        List<OrderInfo> subOrderInfoList = new ArrayList<>();
        //[{"wareId":"1","skuIds":["5","6"]},{"wareId":"2","skuIds":["1"]}]
        for (Map map : mapList) {
            //子订单主表
            OrderInfo subOrderInfo = new OrderInfo();
            BeanUtils.copyProperties(originOrderInfo, subOrderInfo);
            String wareId = (String) map.get("wareId");
            subOrderInfo.setWareId(wareId);
            // id 设置 null
            subOrderInfo.setId(null);
            //设置父订单的ID
            subOrderInfo.setParentOrderId(originOrderInfo.getId());

            List<OrderDetail> orderDetailList = new ArrayList<>();


            for (OrderDetail orderDetail : originOrderDetailList) {
                List<String> skuIds = (List<String>) map.get("skuIds");
                for (String skuId : skuIds) {
                    if (skuId.equals(orderDetail.getSkuId())) {
                        //订单详情表  修改订单主表的外键
                        orderDetailList.add(orderDetail);
                    }
                }
            }
            //子订单总金额
            subOrderInfo.setOrderDetailList(orderDetailList);
            subOrderInfo.sumTotalAmount();
            //保存子订单主表
            orderInfoMapper.insert(subOrderInfo);
            //update order_detail set order_id = 16 where id in (x,x,x,)
            //更新子订单详情表 外键（批量)
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(subOrderInfo.getId());
            List<Long> ids = orderDetailList.stream().map(OrderDetail::getId)
                    .collect(Collectors.toList());
            orderDetailMapper.update(orderDetail,new QueryWrapper<OrderDetail>()
                    .in("id",ids));

            //追加子订单结果
            subOrderInfoList.add(subOrderInfo);
        }
        //将原订单的状态改成订单已折单
        // 修改原始订单的状态
        updateOrderStatus(orderId, ProcessStatus.SPLIT);
        return subOrderInfoList;
    }

    @Override
    public Map initWareOrder(OrderInfo orderInfo) {

        //1：Map  订单表信息
        //2: List<Map> 订单详情信息
        //3: Map.put("detail",List<Map> );
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", orderInfo.getPaymentWay().
                equals( PaymentWay.ONLINE.name())? "2":"1");

        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！

        List<Map> mapArrayList = new ArrayList<> ();
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId", orderDetail.getSkuId());
            orderDetailMap.put("skuNum", orderDetail.getSkuNum());
            orderDetailMap.put("skuName", orderDetail.getSkuName());
            mapArrayList.add(orderDetailMap);
        }
        map.put("details", mapArrayList);
        return map;
    }

    //MQ生产端发消息给仓库　构建仓库所有数据
    public Map initWareOrder(Long orderId){
        OrderInfo orderInfo = getOrderInfo(orderId);
        //1：Map  订单表信息
        //2: List<Map> 订单详情信息
        //3: Map.put("detail",List<Map> );
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", orderInfo.getPaymentWay().
                equals( PaymentWay.ONLINE.name())? "2":"1");

        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！

        List<Map> mapArrayList = new ArrayList<> ();
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId", orderDetail.getSkuId());
            orderDetailMap.put("skuNum", orderDetail.getSkuNum());
            orderDetailMap.put("skuName", orderDetail.getSkuName());
            mapArrayList.add(orderDetailMap);
        }
        map.put("details", mapArrayList);
        return map;

    }

}

